package com.pipi.sso.core.redis.impl;

import com.pipi.sso.core.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.concurrent.TimeUnit;

/**
 * Created by qinyisheng on 16/9/21.
 */
@Component
@Slf4j
public class RedisServiceImpl implements RedisService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private JedisPool jedisPool;

    private Jedis getJedis() {
        try {
            return jedisPool.getResource();
        } catch (Exception e) {
            log.error("redis 挂掉了", e);
        }
        return null;
    }

    @Override
    public Object get(String key) {
        //Jedis jedis = jedisPool.getResource();
        return redisTemplate.boundValueOps(key).get();
        //return jedis.get(key);
    }

    @Override
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public String putJson(String key, String json) {
        Jedis jedis = getJedis();
        try {
            return jedis.set(key, json);
        } catch (Exception e) {
            log.error("redis error:", e);
            jedisPool.returnBrokenResource(jedis);
            jedis = null;
            return null;
        } finally {
            close(jedis);
        }
    }

    @Override
    public Long expire(String key, int second) {
        Jedis jedis = getJedis();
        try {
            return jedis.expire(key, second);
        } catch (Exception e) {
            log.error("redis expire error:", e);
            jedisPool.returnBrokenResource(jedis);
            jedis = null;
        } finally {
            close(jedis);
        }
        return null;
    }

    @Override
    public String getString(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.get(key);
        } catch (Exception e) {
            log.error("redis error:", e);
            jedisPool.returnBrokenResource(jedis);
            jedis = null;
            return null;
        } finally {
            close(jedis);
        }
    }

    @Override
    public Long incr(String tryKey) {
        Jedis jedis = getJedis();
        try {
            return jedis.incr(tryKey);
        } catch (Exception e) {
            log.error("redis error:", e);
            jedisPool.returnBrokenResource(jedis);
            jedis = null;
        } finally {
            close(jedis);
        }
        return null;
    }

    @Override
    public String put(String key, String json, int second) {
        Jedis jedis = getJedis();
        try {
            return jedis.setex(key, second, json);
        } catch (Exception e) {
            log.error("redis error:", e);
            jedisPool.returnBrokenResource(jedis);
            jedis = null;
            return null;
        } finally {
            close(jedis);
        }
    }

    private void close(Jedis jedis) {
        try {
            if (jedis != null) {
                jedisPool.returnResource(jedis);
            }
        } catch (Exception e) {
            //ignore
        }
    }

    public StringRedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public <V> void set(String key, V value) {
        this.set(key, value, -1L);
    }

    @Override
    public <V> void set(String key, V value, long timeMillis) {

        ((BoundValueOperations) (redisTemplate.boundValueOps(key))).set(value);
        if (timeMillis > 0) {
            redisTemplate.expire(key, timeMillis, TimeUnit.MILLISECONDS);
        }

    }

    @Override
    public boolean setNX(String key, String value, int expire) {
        Jedis jedis = getJedis();
        try {
            Long result = jedis.setnx(key, value);
            if (result == 1l) {
                if (expire > 0) {
                    jedis.expire(key, expire);
                }
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("redis error:", e);
            jedisPool.returnBrokenResource(jedis);
            jedis = null;
            return false;
        } finally {
            close(jedis);
        }
    }

    /**
     * 该方法保证了setNX和setEX是原子操作
     * @param key
     * @param value
     * @param expire
     * @return
     */
    @Override
    public boolean setNXNew(final String key, final String value, final int expire) {
        Jedis jedis = getJedis();
        try {
            String result;
            if (expire > 0) {
                result = jedis.set(key, value, "NX", "EX", expire);
            } else {
                result = jedis.set(key, value, "NX");
            }
            log.info("setNXNew return:{}", result);
            if (result != null && result.toUpperCase().equals("OK")) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("redis error:", e);
            jedisPool.returnBrokenResource(jedis);
            jedis = null;
            return false;
        } finally {
            close(jedis);
        }
    }

    @Override
    public <T> T get(String key, Class<T> t) {
        return (T) this.get(key);
    }
}
